package net.gdface.utils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedHashSet;
import java.util.Set;

import static net.gdface.utils.SimpleTypes.getRawClassOfSuperPamamType;
import static net.gdface.utils.SimpleLog.log;

/**
 * 实现接口<I>实例的级联容器 <br>
 * @param <I> 接口类型
 * @author guyadong
 *
 */
public class InterfaceContainer<I>  {
	private final Set<I> listeners = new LinkedHashSet<I>();
	private final Class<I> interfaceClass;
	private boolean skipOnError = true;
	private boolean logOnError = false;

	/**
	 * 接口容器实例
	 */
	public final I container;
	/**
	 * 
	 */
	@SuppressWarnings("unchecked")
	protected InterfaceContainer() {
		interfaceClass = (Class<I>) getRawClassOfSuperPamamType(getClass())[0];
		if(!interfaceClass.isInterface()){
			throw new IllegalArgumentException("param I must be interface");
		}
		// 创建侦听器窗口接口实例
		container = proxyInstance();
	}
	public InterfaceContainer(Class<I> interfaceClass) {
		Assert.notNull(interfaceClass, "interfaceClass");
		if(!interfaceClass.isInterface()){
			throw new IllegalArgumentException("param I must be interface");
		}
		this.interfaceClass = interfaceClass;
		// 创建侦听器窗口接口实例
		container = proxyInstance();
	}
	/**
	 * 根据当前对象创建新的接口实例{@link Proxy}
	 * @return
	 */
	private final I proxyInstance(){
		return interfaceClass.cast(Proxy.newProxyInstance(
				interfaceClass.getClassLoader(),
				new Class<?>[]{ interfaceClass},
				new Handler()));
	}
	/**
	 * 将接口实例加入容器
	 * @param listener
	 */
	public void register(I listener){
		if(listener != null){
			synchronized (this) {
				listeners.add(listener);	
			}
		}
	}
	/**
	 * 从容器中删除指定的接口实例
	 * @param listener
	 */
	public void unregister(I listener){
		if(listener != null){
			synchronized (this) {				
				listeners.remove(listener);	
			}			
		}
	}

	/**
	 * 设置当执行容器中的接口实例有异常抛出时的动作<br>
	 * 为{@code true}时跳过继续执行下一个容器<br>
	 * 为{@code false}时抛出异常
	 * @param skipOnError 当调用抛出异常时是否忽略
	 * @return 当前实例
	 */
	public InterfaceContainer<I> setSkipOnError(boolean skipOnError) {
		this.skipOnError = skipOnError;
		return this;
	}
	
	/**
	 * 设置当执行容器中的接口实例有异常抛出时是否日志输出(仅当skipOnError为true时有效)
	 * @param logOnError 当调用抛出异常时是否输出日志
	 * @return 当前实例
	 */
	public InterfaceContainer<I> setLogOnError(boolean logOnError) {
		this.logOnError = logOnError;
		return this;
	}
	private class Handler implements InvocationHandler{
		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			for(I listener:listeners){
				try {
					method.invoke(listener, args);
				} catch (InvocationTargetException e) {
					Throwable te = e.getTargetException();
					if(skipOnError){			
						if(logOnError){
							//拦截所有异常，保证不影响其他的Listener运行
							log("ERROR:"+te.getMessage(), te);
						}
						continue;
					}
					throw te;
				}catch (Throwable e) {
					throw e;
				} 
			}
			return null;
		}		
	}
}
